#include <iostream>
//#include <iterator>
#include <vector>
#include <set>
#include <list>
#include <fstream>
#include <map>
#include <time.h>
#include <sstream>
#include <cassert>
#include <algorithm>
#include <stdlib.h>
using namespace std;

class Node;

#define WSIZE (sizeof(unsigned)*8)
typedef set<unsigned>settype;

vector<Node *> gPointers;	// associative arrays storing newly added pointer-pointee pairs.
vector<Node *> gPointees;
bool gStayCool = true;
unsigned gEvalNo = 0;
bool debug = 0;

#define MAXNPTRDEREF 100
unsigned nptrderef[MAXNPTRDEREF];

#define checktime(fun, var)	{	\
	starttime = clock();		\
	fun;				\
        endtime = clock();		\
        var += endtime - starttime;	\
}

class DisjointSets
{
public:

	// Create an empty DisjointSets data structure
	DisjointSets();
	// Create a DisjointSets data structure with a specified number of elements (with element id's from 0 to count-1)
	DisjointSets(int count);
    // Copy constructor
    DisjointSets(const DisjointSets & s);
	// Destructor
	~DisjointSets();

	// Find the set identifier that an element currently belongs to.
	// Note: some internal data is modified for optimization even though this method is consant.
	int FindSet(int element) const;
	// Combine two sets into one. All elements in those two sets will share the same set id that can be gotten using FindSet.
	bool Union(int setId1, int setId2);
	// Add a specified number of elements to the DisjointSets data structure. The element id's of the new elements are numbered
	// consequitively starting with the first never-before-used elementId.
	void AddElements(int numToAdd);
	// Returns the number of elements currently in the DisjointSets data structure.
	int NumElements() const;
	// Returns the number of sets currently in the DisjointSets data structure.
	int NumSets() const;

	int getParent(int nn) const;
	
private:

	// Internal Node data structure used for representing an element
	struct Node
	{
		int rank; // This roughly represent the max height of the node in its subtree
		int index; // The index of the element the node represents
		Node* parent; // The parent node of the node
	};

	int m_numElements; // the number of elements currently in the DisjointSets data structure.
	int m_numSets; // the number of sets currently in the DisjointSets data structure.
	std::vector<Node*> m_nodes; // the list of nodes representing the elements
};
DisjointSets::DisjointSets()
{
	m_numElements = 0;
	m_numSets = 0;
}

DisjointSets::DisjointSets(int count)
{
	m_numElements = 0;
	m_numSets = 0;
	AddElements(count);
}

DisjointSets::DisjointSets(const DisjointSets & s)
{
	this->m_numElements = s.m_numElements;
	this->m_numSets = s.m_numSets;

	// Copy nodes
	m_nodes.resize(m_numElements);
	for(int i = 0; i < m_numElements; ++i)
		m_nodes[i] = new Node(*s.m_nodes[i]);

	// Update parent pointers to point to newly created nodes rather than the old ones
	for(int i = 0; i < m_numElements; ++i)
		if(m_nodes[i]->parent != NULL)
			m_nodes[i]->parent = m_nodes[s.m_nodes[i]->parent->index];
}

DisjointSets::~DisjointSets()
{
	for(int i = 0; i < m_numElements; ++i)
		delete m_nodes[i];
	m_nodes.clear();
	m_numElements = 0;
	m_numSets = 0;
}

// Note: some internal data is modified for optimization even though this method is consant.
int DisjointSets::FindSet(int elementId) const
{
	assert(elementId < m_numElements);

	Node* curNode;

	// Find the root element that represents the set which `elementId` belongs to
	curNode = m_nodes[elementId];
	while(curNode->parent) {
		curNode = curNode->parent;
	}
	Node* root = curNode;

	/* The below optimization is removed for inclification.
	// Walk to the root, updating the parents of `elementId`. Make those elements the direct
	// children of `root`. This optimizes the tree for future FindSet invokations.
	curNode = m_nodes[elementId];
	while(curNode != root)
	{
		Node* next = curNode->parent;
		curNode->parent = root;
		curNode = next;
	}*/

	return root->index;
}

bool DisjointSets::Union(int lsetId1, int lsetId2)	// returns changed or not.
{
	// Union operates over representatives. Hence, first call FindSet.
	int setId1 = FindSet(lsetId1);
	int setId2 = FindSet(lsetId2);

	assert(setId1 < m_numElements);
	assert(setId2 < m_numElements);
	bool changed = false;

	if(setId1 == setId2)
		return changed; // already unioned

	Node* set1 = m_nodes[setId1];
	Node* set2 = m_nodes[setId2];

	// Removing the optimization of ranks.
	if (set2->parent != set1) {
		changed = true;
	}
	set2->parent = set1;	// assumes that the stmt is setId1 = setId2.
	// Determine which node representing a set has a higher rank. The node with the higher rank is
	// likely to have a bigger subtree so in order to better balance the tree representing the
	// union, the node with the higher rank is made the parent of the one with the lower rank and
	// not the other way around.
	/*if(set1->rank > set2->rank) {
		if (set2->parent != set1) {
			changed = true;
		}
		set2->parent = set1;
	} else if(set1->rank < set2->rank) {
		if (set1->parent != set2) {
			changed = true;
		}
		set1->parent = set2;
	} else // set1->rank == set2->rank
	{
		if (set2->parent != set1) {
			changed = true;
		}
		set2->parent = set1;
		++set1->rank; // update rank
	}*/

	// Since two sets have fused into one, there is now one less set so update the set count.
	--m_numSets;
	return changed;
}

void DisjointSets::AddElements(int numToAdd)
{
	assert(numToAdd >= 0);

	// insert and initialize the specified number of element nodes to the end of the `m_nodes` array
	m_nodes.insert(m_nodes.end(), numToAdd, (Node*)NULL);
	for(int i = m_numElements; i < m_numElements + numToAdd; ++i)
	{
		m_nodes[i] = new Node();
		m_nodes[i]->parent = NULL;
		m_nodes[i]->index = i;
		m_nodes[i]->rank = 0;
	}

	// update element and set counts
	m_numElements += numToAdd;
	m_numSets += numToAdd;
}

int DisjointSets::NumElements() const
{
	return m_numElements;
}

int DisjointSets::NumSets() const
{
	return m_numSets;
}

int DisjointSets::getParent(int nn) const {
	Node *node = m_nodes[nn]->parent;
	if (node) {
		return node->index;
	} else {
		return m_numElements;
	}
}
void printElementSets(const DisjointSets & s)
{
	for (int i = 0; i < s.NumElements(); ++i)
		cout << s.FindSet(i) << "  ";
	cout << endl;
}

int xmain()
{
	DisjointSets s(10);
	printElementSets(s);
	s.Union(s.FindSet(5),s.FindSet(3));
	printElementSets(s);
	s.Union(s.FindSet(1),s.FindSet(3));
	printElementSets(s);
	s.Union(s.FindSet(6),s.FindSet(7));
	printElementSets(s);
	s.Union(s.FindSet(8),s.FindSet(9));
	printElementSets(s);
	s.Union(s.FindSet(6),s.FindSet(9));
	printElementSets(s);
	s.AddElements(3);
	printElementSets(s);
	s.Union(s.FindSet(11),s.FindSet(12));
	printElementSets(s);
	s.Union(s.FindSet(9),s.FindSet(10));
	printElementSets(s);
	s.Union(s.FindSet(7),s.FindSet(11));
	printElementSets(s);

	return 0;
}

class Node {
public:
	Node(string &name) { init(name); }
	Node() { pointees.clear(); }
	~Node() {}
	void init(string &name) {
		this->name = name;
		pointees.clear();
		Node *defaultPointee = new Node();
		defaultPointee->name = name + "<mem>";
		addPointerTo(defaultPointee);
	}
	string getName() { 
		return name; 
	}
	set<Node *> &getPointees() { return pointees; }
	bool addPointerTo(Node *n) {
		if (pointees.find(n) == pointees.end()) {
			pointees.insert(n);
			gPointers.push_back(this);
			gPointees.push_back(n);
			return true;	// changed.
		} else {
			return false;	// unchanged.
		}
	}
	bool copy(Node *n);
	bool loadFrom(Node *n);
	bool storeTo(Node *n);
	void print();

private:
	set<Node *> pointees;
	string name;
};

bool Node::copy(Node *n) {
	bool changed = false;
	for (set<Node *>::iterator ii = n->pointees.begin(); ii != n->pointees.end(); ++ii) {
		changed |= addPointerTo(*ii);
	}
	return changed;
}
bool Node::loadFrom(Node *n) {
	bool changed = false;
	for (set<Node *>::iterator ii = n->pointees.begin(); ii != n->pointees.end(); ++ii) {
		changed |= this->copy(*ii);
	}
	return changed;
}
bool Node::storeTo(Node *n) {
	bool changed = false;
	for (set<Node *>::iterator ii = pointees.begin(); ii != pointees.end(); ++ii) {
		changed |= (*ii)->copy(n);
	}
	return changed;
}
void Node::print() {
	cout << getName() << ": ";
	for (set<Node *>::iterator ii = pointees.begin(); ii != pointees.end(); ++ii) {
		cout << (*ii)->getName() << ", ";
	}
	cout << "\n";
}

class Constraint {
public:
	enum ConstraintType {AddressOf, Copy, Load, Store};
	Constraint(ConstraintType ctype, Node *dst, Node *src) {
		this->ctype = ctype;
		this->dst = dst;
		this->src = src;
		this->evalno = 0;
	}
	~Constraint() {}
	void print();
	void addDependence(Constraint *to);
	bool operator == (Constraint &c);

	enum ProcessingState {NotProcessed, VisitedOnce, Visited, Processed} state;
public:
	ConstraintType ctype;
	Node *dst, *src;
	set<Constraint *> beforeme;
	unsigned evalno;
};
bool operator < (const Constraint &left, const Constraint &right) {
	if (left.ctype < right.ctype || 
	    (left.ctype == right.ctype && left.dst < right.dst) ||
	    (left.ctype == right.ctype && left.dst == right.dst && left.src < right.src) ||
	    false) {
		return true;
	}
	return false;
}

void Constraint::print() {
	if (ctype == Store) cout << '*';
	cout << dst->getName();
	cout << " = ";
	if (ctype == AddressOf) cout << '&';
	else if (ctype == Load) cout << '*';
	cout << src->getName();
	cout << '\n';
}
bool Constraint::operator == (Constraint &c) {
	if (this->ctype == c.ctype && this->dst == c.dst && this->src == c.src) {
		return true;
	}
	return false;
}
bool lessthanevalno(const Constraint &left, const Constraint &right) {
	return left.evalno < right.evalno;
}
void Constraint::addDependence(Constraint *to) {
	this->beforeme.insert(to);	// for set.
	//this->beforeme.push_back(to);	// for list.
}
class ConstraintSolver {
public:
	ConstraintSolver() {
		constraints.clear();
		nametonode.clear();
		nametoconstraint.clear();
		timeremoveaddressof = timeadddependence = timeinitconstraints = 0;
		timeaddstardependence = timesolvedependence = 0;
	
		aconstraints = NULL;
		nextconstraint = 0;
	}
	~ConstraintSolver() {}

	enum ConstraintStarDependence {DependenceStar00, DependenceStar01, DependenceStar10, DependenceStar11};
	enum ConstraintDependence {DependenceNone, DependenceForward, DependenceBackward, DependenceCyclic};

	unsigned load(string &file);
	unsigned solve();
	bool solve(Constraint *cc);
	Constraint parse(string &cstr);
	Node *getNode(string &name);
	void printConstraints();
	void printPointsToGraph();
	void initConstraints();
	unsigned solveDependence();
	bool solveDependence(Constraint *cc);
	void addDependence();
	void addDependence(Constraint *ii, Constraint *jj);
	ConstraintDependence getDependence(Constraint *ii, Constraint *jj);
	ConstraintStarDependence getStarDependenceRight(Constraint *ii, Constraint *jj);
	ConstraintStarDependence getStarDependenceLeft(Constraint *ii, Constraint *jj);
	void addStarDependence();
	void addStarDependence(Constraint *cc);
	void addStarDependence(Constraint *cc, Node *src);
	void addStarDependence(Node *dst, Node *src);
	void removeAddressOf();
	void printTimes();
	unsigned removeDuplicateConstraints();
	Constraint *getConstraint(Constraint::ConstraintType ctype, Node *dst, Node *src);
	string formName(Constraint::ConstraintType ctype, Node *dst, Node *src);

	unsigned loadgen(string &cfile);
	unsigned loadanders(string &cfile);
	unsigned loadincli(string &cfile);
	void addConstraint(string &cstr);
	void printConstraint(unsigned c[]);
	unsigned solveanders();
	bool solveanders(unsigned c[]);
	unsigned solvegen(unsigned uniperc = 100);
	unsigned solveincli(unsigned uniperc = 100);
	bool solvegen(unsigned c[], bool unify);
	bool setbit(unsigned row, unsigned col);
	bool isset(unsigned row, unsigned col);
	unsigned getnelem();
	unsigned getmem();
	double getderefsize();
	void findnptrderef();
	bool shouldUnify(unsigned uniperc);
	void elongate();
	void elongatesteens();
	vector<settype *> *getbitmap() { return &bitmap; }
	double comparebitmap(vector<settype *> *secondbitmap);
	unsigned getnpointsto(vector<settype *> *bitmap);
	vector<settype *> *intersect(vector<settype *> *secondbitmap);

private:
	vector<Constraint> constraints;
	map<string, Node *> nametonode;
	map<string, Constraint *> nametoconstraint;
	clock_t starttime, endtime;
	double timeremoveaddressof, timeadddependence;	// see initialization in constructor above.
	double timeinitconstraints, timeaddstardependence, timesolvedependence;

	unsigned **aconstraints;
	vector<settype *> bitmap;
	unsigned nconstraints;
	unsigned nextconstraint;

	unsigned *bitmap1;
	DisjointSets *ds;
	unsigned nvars;
};
void ConstraintSolver::printTimes() {
	cout << "remove addressof = " << timeremoveaddressof/CLOCKS_PER_SEC << " sec.\n";
	cout << "add dependence = " << timeadddependence/CLOCKS_PER_SEC << " sec.\n";
	cout << "init constraints = " << timeinitconstraints/CLOCKS_PER_SEC << " sec.\n";
	cout << "add star dependence = " << timeaddstardependence/CLOCKS_PER_SEC << " sec.\n";
	cout << "solve dependence = " << timesolvedependence/CLOCKS_PER_SEC << " sec.\n";
}
unsigned ConstraintSolver::removeDuplicateConstraints() {
	unsigned nRemoved = 0;

	for (unsigned ii = 0; ii < constraints.size() - 1; ++ii) {
		for (unsigned jj = ii + 1; jj < constraints.size(); ++jj) {
			if (constraints[ii] == constraints[jj]) {
				constraints.erase(constraints.begin() + jj);
				--jj;
				++nRemoved;
			}
		}
		cout << "ii=" << ii << ".\n";
	}
	return nRemoved;
}

void ConstraintSolver::printConstraint(unsigned c[]) {
	if (c[2]) cout << "*";
	cout << "v" << c[0] << " = ";
	if (c[6]) cout << "*";
	else if (c[7]) cout << "&";
	cout << "v" << c[4] << "\n";
}
void ConstraintSolver::printConstraints() {
	/*for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		Constraint &c = *ii;
		c.print();
	}*/
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		printConstraint(aconstraints[ii]);
	}
}
void ConstraintSolver::printPointsToGraph() {
	/*for (map<string, Node *>::iterator ii = nametonode.begin(); ii != nametonode.end(); ++ii) {
		ii->second->print();
	}*/
	for (unsigned ii = 0; ii < bitmap.size(); ++ii) {
		cout << "v" << ii << " --> ";
		for (set<unsigned>::iterator it = bitmap[ii]->begin(); it != bitmap[ii]->end(); ++it) {
			cout << "v" << *it << ", ";
		}
		cout << endl;
	}
}
Node *ConstraintSolver::getNode(string &name) {
	if (nametonode[name] == NULL) {
		Node *n = new Node(name);
		nametonode[name] = n;
	}
	return nametonode[name];
}
string ConstraintSolver::formName(Constraint::ConstraintType ctype, Node *dst, Node *src) {
	string namestr = "", ctypestr = "";

	if (ctype == Constraint::AddressOf) ctypestr = "a";
	else if (ctype == Constraint::Copy) ctypestr = "c";
	else if (ctype == Constraint::Load) ctypestr = "l";
	else if (ctype == Constraint::Store) ctypestr = "s";
	else ctypestr = "Invalid Constraint.";

	namestr = ctypestr + "-" + dst->getName() + "-" + src->getName();
	return namestr;
}
Constraint *ConstraintSolver::getConstraint(Constraint::ConstraintType ctype, Node *dst, Node *src) {
	string name = formName(ctype, dst, src);
	if (nametoconstraint[name] == NULL) {
		Constraint *c = new Constraint(ctype, dst, src);
		nametoconstraint[name] = c;
	}
	return nametoconstraint[name];
}
Constraint ConstraintSolver::parse(string &cstr) {
	//// assumptions: the constraint is well formed.
	//// i.e., no constraint of type e.g. *a = *b or &a = b is present.

	size_t eqindex = cstr.find('=');
	if (eqindex == string::npos) {
		cerr << "Error: the constraint does not contain '=': " << cstr << ".\n";
		return Constraint(Constraint::Load, NULL, NULL);
	}
	string left = cstr.substr(0, eqindex);
	string right = cstr.substr(eqindex + 1);

	size_t leftstarindex = left.find('*');
	size_t rightstarindex = right.find('*');
	if (leftstarindex != string::npos) {
		left = left.substr(leftstarindex + 1);
	}
	if (rightstarindex != string::npos) {
		right = right.substr(rightstarindex + 1);
	}

	size_t rightaddressindex = right.find('&');
	if (rightaddressindex != string::npos) {
		right = right.substr(rightaddressindex + 1);
	}
	// now you have right and left with perhaps spaces.
	size_t leftvindex = 0;
	while (left[leftvindex] == ' ') {
		++leftvindex;
	}
	size_t rightvindex = 0;
	while (right[rightvindex] == ' ') {
		++rightvindex;
	}
	size_t leftvendindex = left.size() - 1;
	while (left[leftvendindex] == ' ') {
		--leftvendindex;
	}
	size_t rightvendindex = right.size() - 1;
	while (right[rightvendindex] == ' ') {
		--rightvendindex;
	}
	// now you have right and left with spaces but end of character positions known.
	size_t leftlength = 0, rightlength = 0;

	if (leftvendindex == string::npos) {
		leftlength = string::npos;
	} else {
		leftlength = leftvendindex - leftvindex + 1;
	}
	if (rightvendindex == string::npos) {
		rightlength = string::npos;
	} else {
		rightlength = rightvendindex - rightvindex + 1;
	}

	left = left.substr(leftvindex, leftlength);
	right = right.substr(rightvindex, rightlength);

	// you got the strings without spaces and & and *.
	Constraint::ConstraintType ctype;

	if (rightaddressindex != string::npos) {
		ctype = Constraint::AddressOf;
	} else if (leftstarindex != string::npos) {
		ctype = Constraint::Store;
	} else if (rightstarindex != string::npos) {
		ctype = Constraint::Load;
	} else {
		ctype = Constraint::Copy;
	}
	Node *dst = getNode(left);
	Node *src = getNode(right);

	return *getConstraint(ctype, dst, src);
}

void ConstraintSolver::addConstraint(string &cstr) {
	unsigned left, right, dummy, isstarleft, isstarright, isaddressofright;
	sscanf(cstr.c_str(), "%d %d %d %d %d %d %d %d", &left, &dummy, &isstarleft, &dummy, &right, &dummy, &isstarright, &isaddressofright);
	aconstraints[nextconstraint][0] = left;
	aconstraints[nextconstraint][1] = dummy;
	aconstraints[nextconstraint][2] = isstarleft;
	aconstraints[nextconstraint][3] = dummy;
	aconstraints[nextconstraint][4] = right;
	aconstraints[nextconstraint][5] = dummy;
	aconstraints[nextconstraint][6] = isstarright;
	aconstraints[nextconstraint][7] = isaddressofright;
	++nextconstraint;
}

unsigned ConstraintSolver::loadgen(string &file) {
	ifstream cfile(file.c_str());
	string cstr;

	getline(cfile, cstr);	// no of vars.
	getline(cfile, cstr);	// no of vars.
	sscanf(cstr.c_str(), "%d", &nvars);

	getline(cfile, cstr);	// 0.
	getline(cfile, cstr);	// no of constraints.
	sscanf(cstr.c_str(), "%d", &nconstraints);	

	aconstraints = new unsigned *[nconstraints];
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		aconstraints[ii] = new unsigned [8];
	}

	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		getline(cfile, cstr);
		addConstraint(cstr);
	}

	cfile.close();

	bitmap1 = new unsigned[nvars];	// each bitmap is a single number.
	ds = new DisjointSets(nvars + 1);

	for (unsigned ii = 0; ii < nvars; ++ii) {
		bitmap1[ii] = nvars;	// uninit.
	}

	// init bitmap for extracting final points-to info (elongation).
	bitmap.resize(nvars);	// each bitmap will contain max this many vars.
	for (unsigned ii = 0; ii < nvars; ++ii) {
		bitmap[ii] = new settype();
		bitmap[ii]->clear();
	}
	return nconstraints;
}
unsigned ConstraintSolver::loadanders(string &file) {
	ifstream cfile(file.c_str());
	string cstr;

	getline(cfile, cstr);	// no of vars.
	getline(cfile, cstr);	// no of vars.
	sscanf(cstr.c_str(), "%d", &nvars);

	getline(cfile, cstr);	// 0.
	getline(cfile, cstr);	// no of constraints.
	sscanf(cstr.c_str(), "%d", &nconstraints);	

	aconstraints = new unsigned *[nconstraints];
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		aconstraints[ii] = new unsigned [8];
	}

	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		getline(cfile, cstr);
		addConstraint(cstr);
	}
	cfile.close();

	bitmap.resize(nvars);	// each bitmap will contain max this many vars.
	for (unsigned ii = 0; ii < nvars; ++ii) {
		bitmap[ii] = new settype();
		bitmap[ii]->clear();
	}
	return nconstraints;
}
unsigned ConstraintSolver::loadincli(string &file) {
	ifstream cfile(file.c_str());
	string cstr;

	getline(cfile, cstr);	// no of vars.
	getline(cfile, cstr);	// no of vars.
	sscanf(cstr.c_str(), "%d", &nvars);

	getline(cfile, cstr);	// 0.
	getline(cfile, cstr);	// no of constraints.
	sscanf(cstr.c_str(), "%d", &nconstraints);	

	aconstraints = new unsigned *[nconstraints];
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		aconstraints[ii] = new unsigned [8];
	}

	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		getline(cfile, cstr);
		addConstraint(cstr);
	}
	cfile.close();

	bitmap.resize(nvars);	// each bitmap will contain max this many vars.
	bitmap1 = new unsigned[nvars];	// each bitmap is a single number.
	ds = new DisjointSets(nvars + 1);

	for (unsigned ii = 0; ii < nvars; ++ii) {
		bitmap[ii] = new settype();
		bitmap[ii]->clear();
		bitmap1[ii] = nvars;	// uninit.
	}

	return nconstraints;
}
unsigned ConstraintSolver::load(string &file) {
	ifstream cfile(file.c_str());
	string cstr;
	
	getline(cfile, cstr);
	while (cfile.good()) {
		constraints.push_back(parse(cstr));
		getline(cfile, cstr);
	}
	cfile.close();

	/*sort(constraints.begin(), constraints.end());
	vector<Constraint>::iterator it = unique(constraints.begin(), constraints.end());
	constraints.erase(it, constraints.end());*/

	return constraints.size();
}
bool ConstraintSolver::solve(Constraint *cc) {
	bool changed = false;

	gPointers.clear();
	gPointees.clear();

	switch (cc->ctype) {
	case Constraint::AddressOf:	// a = &b.
		changed = cc->dst->addPointerTo(cc->src);
		break;
	case Constraint::Copy:		// a = b.
		changed = cc->dst->copy(cc->src);
		break;
	case Constraint::Load:		// a = *b.
		changed = cc->dst->loadFrom(cc->src);
		break;
	case Constraint::Store:		// *a = b.
		changed = cc->dst->storeTo(cc->src);
		break;
	default:
		cout << "Error: invalid constraint.\n";
		return false;
	}
	return changed;
}
ConstraintSolver::ConstraintStarDependence ConstraintSolver::getStarDependenceLeft(Constraint *ii, Constraint *jj) {
	// 00 means a=... and ...=a.
	// 11 means *a=... and ...=*a.
	// 10 means *a=... and ...=a.
	// 01 means a=... and ...=*a.
	if (ii->ctype != Constraint::Store && (jj->ctype == Constraint::Copy || jj->ctype == Constraint::Store))
		return DependenceStar00;
	if (ii->ctype == Constraint::Store && jj->ctype == Constraint::Load)
		return DependenceStar11;
	if (ii->ctype == Constraint::Store && (jj->ctype == Constraint::Copy || jj->ctype == Constraint::Store))
		return DependenceStar10;
	if (ii->ctype != Constraint::Store && jj->ctype == Constraint::Load)
		return DependenceStar01;
}
ConstraintSolver::ConstraintStarDependence ConstraintSolver::getStarDependenceRight(Constraint *ii, Constraint *jj) {
	// 00 means ...=a and a=....
	// 11 means ...=*a and *a=....
	// 10 means ...=*a and a=....
	// 01 means ...=a and *a=....
	if ((ii->ctype == Constraint::Copy || ii->ctype == Constraint::Store) && jj->ctype != Constraint::Store)
		return DependenceStar00;
	if (ii->ctype == Constraint::Load && jj->ctype == Constraint::Store)
		return DependenceStar11;
	if (ii->ctype == Constraint::Load && jj->ctype != Constraint::Store)
		return DependenceStar10;
	if ((ii->ctype == Constraint::Copy || ii->ctype == Constraint::Store) && jj->ctype == Constraint::Load)
		return DependenceStar01;
}
ConstraintSolver::ConstraintDependence ConstraintSolver::getDependence(Constraint *ii, Constraint *jj) {
	ConstraintStarDependence csdleft = getStarDependenceLeft(ii, jj);
	ConstraintStarDependence csdright = getStarDependenceRight(ii, jj);
	/*if (ii->dst == jj->src && jj->dst == ii->src && 
	    (csdleft == DependenceStar00 || csdleft == DependenceStar11) &&
	    (csdright == DependenceStar00 || csdright == DependenceStar11)) {
		return DependenceCyclic;
	}*/	///////// let's not bother about cycles here.
	if (ii->dst == jj->src && csdleft != DependenceStar10) return DependenceForward;
	if (jj->dst == ii->src && csdright != DependenceStar01) return DependenceBackward;
	if (ii->dst == jj->dst && ii->ctype != Constraint::Store && jj->ctype == Constraint::Store) return DependenceForward;
	if (ii->dst == jj->dst && ii->ctype == Constraint::Store && jj->ctype != Constraint::Store) return DependenceBackward;
	return DependenceNone;
}
void ConstraintSolver::addDependence(Constraint *ii, Constraint *jj) {
	ConstraintDependence cd = getDependence(ii, jj);
	switch (cd) {
	case DependenceBackward:
		ii->addDependence(jj);	// jj happens before ii.
		break;
	case DependenceForward:
		jj->addDependence(ii);
		break;
	case DependenceCyclic:
		ii->addDependence(jj);	//// not adding both ways.
		break;
	default:	// DependenceNone.
		break;
	}
}
void ConstraintSolver::addDependence() {
	for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		for (vector<Constraint>::iterator jj = ii + 1; jj != constraints.end(); ++jj) {
			addDependence(const_cast<Constraint *>(&*ii), const_cast<Constraint *>(&*jj));
		}
	}
}

unsigned ConstraintSolver::solve() {
	bool changed = false;
	unsigned niterations = 0;

	do {
		changed = false;
		for (unsigned ii = 0; ii < constraints.size(); ++ii) {
			changed |= solve(&constraints[ii]);
		}
		++niterations;
		//cout << "Iteration " << niterations << "\n";

	} while(changed);
	return niterations;
}
bool ConstraintSolver::solveDependence(Constraint *cc) {
	bool changed = false;

	switch (cc->state) {
	case Constraint::Processed:
		return changed;

	case Constraint::VisitedOnce:
	case Constraint::NotProcessed:
		if (cc->state == Constraint::NotProcessed) cc->state = Constraint::VisitedOnce;
		else if (cc->state == Constraint::VisitedOnce) cc->state = Constraint::Visited;
		for (set<Constraint *>::iterator beforemeii = cc->beforeme.begin(); beforemeii != cc->beforeme.end(); ++beforemeii) {
			changed |= solveDependence(*beforemeii);
		}
		break;

	case Constraint::Visited:
		// cycle.
		//cout << "\tcycle detected.\n";
		break;

	default:
		cout << "Error: invalid constraint state.\n";
		break;
	}
	changed |= solve(cc);
	cc->state = Constraint::Processed;
	cc->evalno = gEvalNo++;
	return changed;
}
void ConstraintSolver::initConstraints() {
	for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		ii->state = Constraint::NotProcessed;
	}
}

void ConstraintSolver::addStarDependence(Node *dst, Node *src) {
	// add dependence from ... = src to *dst = ....
	vector<Constraint *> earliers, laters;

	for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		if (ii->dst == dst && ii->ctype == Constraint::Store) {
			earliers.push_back(&*ii);
		}
		if (ii->src == src && (ii->ctype == Constraint::Copy || ii->ctype == Constraint::Store)) {
			laters.push_back(&*ii);
		}
	}
	for (vector<Constraint *>::iterator eii = earliers.begin(); eii != earliers.end(); ++eii) {
		for (vector<Constraint *>::iterator lii = laters.begin(); lii != laters.end(); ++lii) {
			(*lii)->addDependence(*eii);
		}
	}
}
void ConstraintSolver::addStarDependence(Constraint *cc, Node *src) {
	for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		if (ii->src == src && (ii->ctype == Constraint::Copy || ii->ctype == Constraint::Store)) {
			ii->addDependence(cc);
		}
	}
}
void ConstraintSolver::addStarDependence(Constraint *cc) {
	if (cc->ctype != Constraint::Store) return;

	set<Node *> &pointees = cc->dst->getPointees();
	for (set<Node *>::iterator ii = pointees.begin(); ii != pointees.end(); ++ii) {
		addStarDependence(cc, *ii);
	}
}
void ConstraintSolver::addStarDependence() {
	for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		addStarDependence(&*ii);
	}
}

void ConstraintSolver::removeAddressOf() {
	gStayCool = true;
	for (unsigned ii = 0; ii < constraints.size(); ++ii) {
		if (constraints[ii].ctype == Constraint::AddressOf) {
			solve(&constraints[ii]);
			constraints.erase(constraints.begin() + ii);
			--ii;
		}
	}
	gStayCool = false;
}

unsigned ConstraintSolver::solveDependence() {
	/*checktime(removeAddressOf(),timeremoveaddressof);
	checktime(addDependence(), timeadddependence);
	checktime(addStarDependence(), timeaddstardependence);*/

	unsigned niterations = 0;
	bool changed = false;

	/*checktime(initConstraints(), timeinitconstraints);
	for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
		changed |= solveDependence(&*ii);
	}
	++niterations;
	// evalno of constraints are set.
	sort(constraints.begin(), constraints.end(), lessthanevalno);
	*/
	
	do {
		//cout << "\nIteration " << (niterations + 1) << "\n";
		changed = false;
		//checktime(initConstraints(), timeinitconstraints);
		for (vector<Constraint>::iterator ii = constraints.begin(); ii != constraints.end(); ++ii) {
			changed |= solve(&*ii);	// no solveDependence.
		}
		++niterations;
	} while (changed);
	return niterations;
}
bool ConstraintSolver::isset(unsigned row, unsigned col) {
	/*unsigned word = col/WSIZE;
	unsigned wordbit = col % WSIZE;

	unsigned andword = 1 << (WSIZE - wordbit - 1);
	return bitmap[row][word] & andword;*/
	return 0;
}
bool ConstraintSolver::setbit(unsigned row, unsigned col) {
	/*unsigned word = col/WSIZE;
	unsigned wordbit = col % WSIZE;

	unsigned orword = 1 << (WSIZE - wordbit - 1);
	unsigned ori = bitmap[row][word];
	bitmap[row][word] |= orword;
	if (ori != bitmap[row][word]) {
		return true;
	}
	return false;*/
	return 0;
}

bool ConstraintSolver::solvegen(unsigned c[], bool unify) {
	bool changed = false;
	unsigned ori = 0;
	unsigned src = ds->FindSet(c[4]);
	unsigned dst = ds->FindSet(c[0]);
	unsigned niter = 0;

	if (c[2]) {	// store.
		if (bitmap1[dst] == nvars) {	// uninit.
			changed = false;
		} else {
			unsigned stardst = ds->FindSet(bitmap1[dst]);
			if (bitmap1[stardst] == nvars) {
				bitmap1[stardst] = bitmap1[src];
				changed = (bitmap1[src] != nvars);
			} else if (bitmap1[src] != nvars) {
				int ptr1 = bitmap1[stardst];
				int ptr2 = bitmap1[src];
				do {
					changed |= ds->Union(ptr1, ptr2);
					ptr1 = bitmap1[ptr1];
					ptr2 = bitmap1[ptr2];
				} while (changed && ptr1 != ptr2 && ptr1 != nvars && ptr2 != nvars && bitmap1[ptr1] != ptr1 && bitmap1[ptr2] != ptr2 && ++niter < 10);
				if (changed) bitmap1[stardst] = ds->FindSet(bitmap1[src]);
			} else {
				changed = true;
				bitmap1[src] = bitmap1[stardst];
			}
		}
	} else if (c[6]) {	// load.
		if (bitmap1[src] == nvars) {	// uninit.
			changed = false;
		} else {
			unsigned starsrc = ds->FindSet(bitmap1[src]);
			if (bitmap1[dst] == nvars) {
				bitmap1[dst] = bitmap1[starsrc];
				changed = (bitmap1[starsrc] != nvars);
			} else if (bitmap1[starsrc] != nvars) {
				int ptr1 = bitmap1[dst];
				int ptr2 = bitmap1[starsrc];
				do {
					changed |= ds->Union(ptr1, ptr2);
					ptr1 = bitmap1[ptr1];
					ptr2 = bitmap1[ptr2];
				} while (changed && ptr1 != ptr2 && ptr1 != nvars && ptr2 != nvars && bitmap1[ptr1] != ptr1 && bitmap1[ptr2] != ptr2 && ++niter < 10);
				if (changed) bitmap1[dst] = ds->FindSet(bitmap1[starsrc]);
			} else {
				changed = true;
				bitmap1[starsrc] = bitmap1[dst];
			}
		}
	} else if (c[7]) {	// addressof.
		if (bitmap1[dst] == nvars) {	// uninit.
			bitmap1[dst] = src;
			changed = true;
		} else {
			int ptr1 = bitmap1[dst];
			int ptr2 = src;
			do {
				changed |= ds->Union(ptr1, ptr2);
				ptr1 = bitmap1[ptr1];
				ptr2 = bitmap1[ptr2];
			} while (changed && ptr1 != ptr2 && ptr1 != nvars && ptr2 != nvars && bitmap1[ptr1] != ptr1 && bitmap1[ptr2] != ptr2 && ++niter < 10);
			if (changed) bitmap1[dst] = ds->FindSet(src);
		}
	} else {		// copy.
		if (bitmap1[dst] == nvars) {	// uninit.
			bitmap1[dst] = bitmap1[src];
			changed = (bitmap1[src] != nvars);
		} else if (bitmap1[src] != nvars) {
			int ptr1 = bitmap1[dst];
			int ptr2 = bitmap1[src];
			do {
				changed |= ds->Union(ptr1, ptr2);
				ptr1 = bitmap1[ptr1];
				ptr2 = bitmap1[ptr2];
			} while (changed && ptr1 != ptr2 && ptr1 != nvars && ptr2 != nvars && bitmap1[ptr1] != ptr1 && bitmap1[ptr2] != ptr2 && ++niter < 10);
			if (changed) bitmap1[dst] = ds->FindSet(bitmap1[src]);
		} else {	// src has empty points to set and dst does not.
			changed = true;
			bitmap1[src] = bitmap1[dst];
		}
	}
	/*for (unsigned ii = 0; ii < nvars; ++ii) {
		cout << "bitmap1[" << ii << "] = " << bitmap1[ii] << endl;
	}*/
	return changed;
}
bool ConstraintSolver::shouldUnify(unsigned uniperc) {	// returns true if the constraint needs to be processed as unification.
	int somerand = rand() % 100;
	return (somerand < uniperc);
}
unsigned ConstraintSolver::solveincli(unsigned uniperc/* = 100*/) {
	// process uniperc % constraints as unification and the remaining as inclusion.
	// unification done once, inclusion iteratively.
	unsigned niterationsuni = 0, niterationsinclu = 0;
	bool changed = false;
	vector<unsigned> uniconstraints, incluconstraints;

	uniconstraints.clear();
	incluconstraints.clear();
	
	clock_t start = clock();
	clock_t end, inclitime;
	// separate uni and inclu constraints.
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		bool unify = shouldUnify(uniperc);
		if (unify) {
			uniconstraints.push_back(ii);
		} else {
			incluconstraints.push_back(ii);
		}
	}

	unsigned nouteriterations = 0;
	do {
	
	// unification.
	do {
		changed = false;

		for (vector<unsigned>::iterator it = uniconstraints.begin(); it != uniconstraints.end(); ++it) {
			changed |= solvegen(aconstraints[*it], true);
		}
		++niterationsuni;
	} while (changed);
	
	end = clock();
	inclitime = end - start;
	elongate();	// convert union-find to vector.
	
	start = clock();
	// inclusion.
	do {
		changed = false;

		for (vector<unsigned>::iterator it = incluconstraints.begin(); it != incluconstraints.end(); ++it) {
			changed |= solveanders(aconstraints[*it]);
		}
		++niterationsinclu;
		cout << "iteration: " << niterationsinclu << endl;
	} while (changed);

	} while (++nouteriterations < 0);
	end = clock();
	inclitime += end - start;

	inclitime = inclitime/CLOCKS_PER_SEC;
	//cout << "Time = " << inclitime << " seconds.\n";
	return niterationsuni + niterationsinclu;
}
unsigned ConstraintSolver::solvegen(unsigned uniperc/* = 100*/) {
    unsigned niterations = 0;
    bool changed = false;
    unsigned nunify = 0, ninclu = 0;

    srand(time(NULL));

    do {
	changed = false;
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		bool unify = shouldUnify(uniperc);
		if (unify) {
			++nunify;
		} else {
			++ninclu;
		}
		//printConstraint(aconstraints[ii]);
		changed |= solvegen(aconstraints[ii], unify);
		//elongatesteens();
		//printPointsToGraph();
	}
	++niterations;
	std::cout << "----------- Iteration " << niterations << " over." << std::endl;
    } while (changed);

	cout << "Number of total sets in the end: " << ds->NumSets() << "\n";
	cout << "nunify = " << nunify << ", ninclu = " << ninclu << ".\n";

    return niterations;
}
bool ConstraintSolver::solveanders(unsigned c[]) {
	bool changed = false;
	unsigned ori = 0;

	if (c[2]) {	// store.
		for (set<unsigned>::iterator ii = bitmap[c[0]]->begin(); ii != bitmap[c[0]]->end(); ++ii) {
			ori = bitmap[*ii]->size();
			set_union(bitmap[*ii]->begin(), bitmap[*ii]->end(), bitmap[c[4]]->begin(), bitmap[c[4]]->end(), inserter(*bitmap[*ii], bitmap[*ii]->end()));
			changed |= (bitmap[*ii]->size() != ori);
		}
	} else if (c[6]) {	// load.
		for (set<unsigned>::iterator ii = bitmap[c[4]]->begin(); ii != bitmap[c[4]]->end(); ++ii) {
			ori = bitmap[c[0]]->size();
			//set_union(bitmap[c[0]].begin(), bitmap[c[0]].end(), bitmap[*ii].begin(), bitmap[*ii].end(), bitmap[c[0]].end());
			set_union(bitmap[c[0]]->begin(), bitmap[c[0]]->end(), bitmap[*ii]->begin(), bitmap[*ii]->end(), inserter(*bitmap[c[0]], bitmap[c[0]]->end()));
			changed |= (bitmap[c[0]]->size() != ori);
		}
	} else if (c[7]) {	// addressof.
		ori = bitmap[c[0]]->size();
		bitmap[c[0]]->insert(c[4]);
		changed = (bitmap[c[0]]->size() != ori);
	} else {		// copy.
		ori = bitmap[c[0]]->size();
		//set_union(bitmap[c[0]].begin(), bitmap[c[0]].end(), bitmap[c[4]].begin(), bitmap[c[4]].end(), bitmap[c[0]].end());
		set_union(bitmap[c[0]]->begin(), bitmap[c[0]]->end(), bitmap[c[4]]->begin(), bitmap[c[4]]->end(), inserter(*bitmap[c[0]], bitmap[c[0]]->end()));
		changed = (bitmap[c[0]]->size() != ori);
	}
	return changed;
}
unsigned ConstraintSolver::solveanders() {
    unsigned niterations = 0;
    bool changed = false;

    do {
	changed = false;
	for (unsigned ii = 0; ii < nconstraints; ++ii) {
		//printConstraint(aconstraints[ii]);
		changed |= solveanders(aconstraints[ii]);
	}
	++niterations;
	//std::cout << "----------- Iteration " << niterations << std::endl;
	//printPointsToGraph();
	//std::cout << std::endl;
    } while (changed);

    return niterations;
}

unsigned ConstraintSolver::getnelem() {
	unsigned nelem = 0;
	for (vector<settype *>::iterator ii = bitmap.begin(); ii != bitmap.end(); ++ii) {
		nelem += (*ii)->size();
	}
	return nelem;
}
double ConstraintSolver::getderefsize() {
	return getnelem()*1.0/bitmap.size();
}
unsigned ConstraintSolver::getmem() {
	/*unsigned nelem = 0;
	for (vector<settype>::iterator ii = bitmap.begin(); ii != bitmap.end(); ++ii) {
		nelem += ii->size();
	}
	nelem += bitmap.size();
	return nelem*sizeof(unsigned);
	*/
	return (getnelem() + bitmap.size())*sizeof(unsigned);
}

void ConstraintSolver::findnptrderef() {
	// init to 0.
	for (unsigned jj = 0; jj < MAXNPTRDEREF; ++jj) {
		nptrderef[jj] = 0;
	}
	// count.
	for (vector<settype *>::iterator ii = bitmap.begin(); ii != bitmap.end(); ++ii) {
		if ((*ii)->size() > MAXNPTRDEREF) ++nptrderef[MAXNPTRDEREF-1];
		else ++nptrderef[(*ii)->size()];
	}
	// print.
	for (unsigned jj = 0; jj < MAXNPTRDEREF; ++jj) {
		//cout << jj << "\t" << nptrderef[jj] << endl;
		cout << nptrderef[jj] << endl;
	}
}
void get_mem_usage(){
  unsigned x= 0;
  std::ifstream in("/proc/self/status");
  while(in){
    std::string line, tag;
    getline(in, line);
    std::istringstream iss(line);
    iss>>tag;
    if(tag == "VmData:"){
      iss>>x;
      break;
    }
  }
  in.close();
        std::cerr << "Memory = " << (x+512)/1024 << " MB.\n";
  return;
}


unsigned ConstraintSolver::getnpointsto(vector<settype *> *bitmap) {
	unsigned count = 0;
	for (vector<settype *>::iterator vit = bitmap->begin(); vit != bitmap->end(); ++vit) {
		settype *oneset = *vit;
		count += oneset->size();
	}
	return count;
}
vector<settype *> *ConstraintSolver::intersect(vector<settype *> *secondbitmap) {
	// return the bitmap of common pointees between this->bitmap and secondbitmap.
	unsigned oneii = 0;
	vector<settype *> *result = new vector<settype *>(nvars);
	result->resize(nvars);
	for (unsigned ii = 0; ii < nvars; ++ii) {
		(*result)[ii] = new settype();
		(*result)[ii]->clear();
	}

	for (vector<settype *>::iterator oneit = bitmap.begin(); oneit != bitmap.end(); ++oneit, ++oneii) {
		settype *oneset = *oneit;
		settype *twoset = (*secondbitmap)[oneii];
		settype *resultset = (*result)[oneii];
		for (settype::iterator onesetit = oneset->begin(); onesetit != oneset->end(); ++onesetit) {
			unsigned pointee = *onesetit;
			// oneii is pointing to pointee.
			if (twoset->find(pointee) != twoset->end()) {
				resultset->insert(pointee);
			}
		}
	}
	return result;
}
double ConstraintSolver::comparebitmap(vector<settype *> *secondbitmap) {
	// returns the percentage of points-to information secondbitmap has of the bitmap.
	// this.bitmap == superset (usually steensgaard), secondbitmap == subset.
	unsigned npointsto = getnpointsto(&bitmap);
	unsigned secondnpointsto = getnpointsto(secondbitmap);
	cout << "\t100 * " << secondnpointsto << " / " << npointsto << endl;
	return (double)secondnpointsto*100.0/npointsto;
	
}
void ConstraintSolver::elongatesteens() {
	// converts points-to info from union-find to set of pointees for steensgaard's analysis.

	for (unsigned ii = 0; ii < nvars; ++ii) {
		int iirepr = ds->FindSet(ii);
		bitmap1[ii] = bitmap1[iirepr];	// my points-to info is my repr's points-to info.
	}
	for (unsigned ii = 0; ii < nvars; ++ii) {
		if (bitmap1[ii] != nvars && bitmap1[ii] != (nvars+1)) {
			////bitmap[ii]->insert(bitmap1[ii]);	// representative.
			int bitmap1repr = ds->FindSet(bitmap1[ii]);
			for (unsigned jj = 0; jj < nvars; ++jj) {
				int repr = ds->FindSet(jj);
				if (repr == bitmap1repr) {
					bitmap[ii]->insert(jj);
				}
			}
		}
	}

}
void ConstraintSolver::elongate() {
	// converts points-to info from union-find to set of pointees assuming part of it to be andersens.
	bool changed = false;

	/*for (unsigned ii = 0; ii < nvars; ++ii) {
		int iirepr = ds->FindSet(ii);
		bitmap1[ii] = bitmap1[iirepr];	// my points-to info is my repr's points-to info.
	}*/
	// first the representative.
	for (unsigned ii = 0; ii < nvars; ++ii) {
		//cout << "bitmap1[" << ii << "] = " << bitmap1[ii] << endl;
		if (bitmap1[ii] != nvars && bitmap1[ii] != (nvars+1)) {
			//cout << "bitmap[" << ii << "].insert(" << bitmap1[ii] << ")" << endl;
			bitmap[ii]->insert(bitmap1[ii]);
		}
	}
	// then the children of the representative, level by level.
	unsigned niterations = 0;
	do {
		changed = false;
		for (unsigned ii = 0; ii < nvars; ++ii) {
			int parent = ds->getParent(ii);
			if (parent != nvars && parent != (nvars+1)) {
				//cout << "ii = " << ii << ", parent = " << parent << endl;
				for (unsigned jj = 0; jj < nvars; ++jj) {
					if (bitmap[jj]->find(parent) != bitmap[jj]->end() && bitmap[jj]->find(ii) == bitmap[jj]->end()) {
						//cout << "\tjj = " << jj << endl;
						bitmap[jj]->insert(ii);
						changed = true;
					}
				}
			}

		}
		cout << "\tinner niterations = " << ++niterations << endl;
	} while (changed);
}
int main(int argc, char *argv[]) {
    //unsigned ntotaliterations = 0;
    char *number[] = {"176", "253", "255", "252", "197", "254", "175", "186",
                      "177", "188", "300", "164", "256", "181", "183", "179"};
    for (unsigned ii = 0; ii < 1; ++ii) {
	ConstraintSolver cs, cs2, csanders, cssteens;
	//string file = string("gen/spec") + number[ii] + ".gen";
	if (argc != 2) {
		cout << "Usage: " << argv[0] << " <file.gen>" << endl;
		exit(1);
	}
	string file = argv[1];
	unsigned nconstraintssteens = cssteens.loadgen(file);
	unsigned niterationssteens = cssteens.solvegen();
	cssteens.elongatesteens();
	//cssteens.printPointsToGraph();
	cout << "Steensgaard's analysis over.\n";
	cout << "--------------------------------------\n";
	/*unsigned nconstraintsanders = csanders.loadanders(file);
	unsigned niterationsanders = csanders.solveanders();
	double percanders = cssteens.comparebitmap(csanders.getbitmap());
	cout << "anders = " << percanders << "% steens.\n";
	cout << "Andersen's analysis over.\n";
	cout << "--------------------------------------\n";
	*/

	unsigned nconstraints = cs.loadincli(file);
	unsigned niterations = cs.solveincli((unsigned)90);
	double perc = cssteens.comparebitmap(cs.getbitmap());
	cout << "90% uni + 10% incl = " << perc << "%inclification.\n";
	//ntotaliterations += niterations;
	cout << "Inclification one over.\n";
	cout << "--------------------------------------\n";
	unsigned nconstraints2 = cs2.loadincli(file);
	unsigned niterations2 = cs2.solveincli((unsigned)90);
	double perc2 = cssteens.comparebitmap(cs2.getbitmap());
	cout << "90% uni + 10% incl = " << perc2 << "%inclification.\n";
	cout << "Inclification two over.\n";
	cout << "--------------------------------------\n";

	vector<settype *> *interbitmap = cs.intersect(cs2.getbitmap());
	double percinter = cssteens.comparebitmap(interbitmap);
	cout << "Intersection = " << percinter << "%" << endl;

	//cout << file << " " << nconstraints << "--------------------\n";
	//cout << file << " " << niterations << "--------------------\n";
	//cout << file << " " << cs.getmem()/1000.0 << " KB\n";
	//cout << file << " " << cs.getderefsize() << "\n";
	//cout << file << "\t" << nconstraintsanders << "\t" << niterationsanders << endl;

	//cs.findnptrderef();
	//cout << "--------------------------------------\n";
	//cs.printConstraints();
	//cs.printPointsToGraph();
	//cs.printTimes();
    }
    /*for (unsigned ii = 1; ii < 55; ++ii) {
	ConstraintSolver cs;
	char number[5];
	sprintf(number, "%d", ii);
	string file = string("g") + number + ".constraints";
	//string file = "r0.constraints";
	cs.load(file);
	unsigned niterations = cs.solveDependence();
	ntotaliterations += niterations;
	cout << niterations << "\n";
	//cout << file << " " << cs.solveDependence() << "\n";
	//cs.printConstraints();
	//cs.printPointsToGraph();
    }*/

    //out << "Total iterations: " << ntotaliterations << "\n";
	//get_mem_usage();

	return 0;
}
